package com.geekhalo.demo.mq.event.fix;

import com.geekhalo.demo.mq.event.Order;
import com.geekhalo.demo.util.SleepUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.net.SocketTimeoutException;
import java.util.concurrent.*;

@Component
@Slf4j
public class SMSSendNoticeListener {
    /**
     * 1. 对 OrderPaidEvent 事件进行处理 <br />
     * 2. 使用 sendSMSTaskExecutorService 线程池进行异步处理
     * @param event
     */
    @EventListener
    @Async("sendSMSTaskExecutorService")
    public void handle(OrderPaidEvent event){
        sendSMSNotice(event.getOrder());
    }

    @SneakyThrows
    protected void sendSMSNotice(Order order) {
        if (order.getId() % 5 == 0){
            SleepUtil.sleep(10);
            throw new SocketTimeoutException();
        }
    }

    @Bean
    public Executor sendSMSTaskExecutorService(){
        // 核心线程数 为 CPU 数量
        int coreThreads = Runtime.getRuntime().availableProcessors();
        // 【控制资源】最大线程数 为 核心线程数 的 5 倍
        int maxThreads = coreThreads * 5;
        // 【控制资源】队列长度为 1024
        BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(1024);
        // 【避免阻塞】线程 和 队列 资源耗尽后，直接抛弃最老的任务，避免造成阻塞
        RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.DiscardOldestPolicy();
        // 自定义线程工厂
        BasicThreadFactory threadFactory = new BasicThreadFactory.Builder()
                .namingPattern("SMS-Send-Thread-%d")
                .daemon(true)
                .uncaughtExceptionHandler((t, e) -> log.error("Failed to run task", e))
                .build();
        // 自定义线程池
        return new ThreadPoolExecutor(coreThreads, maxThreads,
                5, TimeUnit.MINUTES,
                queue,
                threadFactory,
                rejectedExecutionHandler
        );
    }
}
